package cn.hpclub.server.service;

import cn.hpclub.server.constant.ClientApiConstant;
import cn.hpclub.server.constant.Constant;
import cn.hpclub.server.constant.H5ApiConstant;
import cn.hpclub.server.exception.CheckOrderException;
import cn.hpclub.server.model.CmccOrder;
import cn.hpclub.server.model.RechargeOrder;
import cn.hpclub.server.model.SysCodeType;
import cn.hpclub.server.model.SysCodeValue;
import cn.hpclub.server.util.HttpUtil;
import cn.hpclub.server.util.SystemConfigUtil;
import cn.hpclub.server.util.wxpay.WxpayConfig;
import com.google.common.net.MediaType;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Created by tracy on 2017/8/10.
 */
public class RefundService {
    private static final Logger logger = LoggerFactory.getLogger(RefundService.class);
    public static RefundService service = new RefundService();
    public static final String HOST_PREFIX = SystemConfigUtil.getSystemConfig().getHostPrefix();
    private static final String RETURN_CODE = "RETURN_CODE";
    private static final String RETURN_MSG = "RETURN_MSG";
    private static final String SUC_CODE = "000000";

    private static final String ORDER_NOT_EXIST = "订单不存在";
    private static final String PAY_STATUS_ERROR = "该订单支付状态不能退款：";
    private static final String PAY_STATUS_ERROR_SEARCH = "该订单支付状态不能查询：";
    private static final String AMOUNT_ERROR = "退款金额有误";
    public static final String ILLEGAL_ORDER = "非法订单，暂只支持选号入网和充值缴费订单";
    public static final String ILLEGAL_ORDER_SARCH = "非法订单，暂只支持充值缴费订单";
    public static final String HOST_REFUND = SystemConfigUtil.getSystemConfig().getRefundUri();

    /**
     * @param orderId void
     * @return
     * @Title: refund
     * @Description:手动退费
     */
    public JSONObject refund(String orderId, String amount) {
        JSONObject jo;
        // TODO Auto-generated method stub
        String type = getServiceType(orderId);
        int payPlat = 0;
        int payChannel = 0;
        if (Constant.PayServiceType.RECHARGE.equals(type)) {
            RechargeOrder order = RechargeOrder.dao.getRechargeOrderByOrderId(orderId);
            payPlat = order.get(RechargeOrder.PAY_PLAT);
            payChannel = order.get(CmccOrder.PAY_CHANNEL)!=null?order.getInt(CmccOrder.PAY_CHANNEL):0;
        } else if (Constant.PayServiceType.PACKAGE.equals(type)) {
            CmccOrder order = CmccOrder.dao.getOrderInfo(orderId);
            payPlat = order.get(CmccOrder.PAY_PLAT);
            payChannel = order.get(CmccOrder.PAY_CHANNEL)!=null?order.getInt(CmccOrder.PAY_CHANNEL):0;
        }
        jo = webRefund(orderId, amount, payPlat, payChannel);
        return jo;
    }

    /**
     * @param orderId    退费订单号
     * @param amount     金额
     * @param payPlat    支付方式  14-支付宝、15-建设银行、16-银联、20-微信、25-农行
     * @param payChannel 支付产品类型：1-H5、2-APP、3-HTML(微信公众账号)
     * @return JSONObject
     * @Title: webRefund
     * @Description:后台退费接口，能看到菜单的都可以退费，其退费开关 由权限来控制
     */
    public JSONObject webRefund(String orderId, String amount, int payPlat, int payChannel) {
        logger.info("to refund");
        JSONObject jo = setResponseObj(ClientApiConstant.ResultCode.FAILED, ClientApiConstant.Msg.FAIL,
                ClientApiConstant.Msg.EMPTY);
        try {
            logger.info(orderId + ":" + amount);
            // 核对订单数据,不正确会抛异常，都正确才能往下走
            checkOrder(orderId, amount);
            String r = "";

            String RETURN_CODE = "";
            String msg = "";

            if (payPlat == 15 || payPlat == 16) {//调用建行退费
                r = HttpUtil.syncPostJsonBody(getCCBRefundUrl(), MediaType.FORM_DATA, "orderId=" + orderId + "&amount=" + amount, 15000);
                JSONObject result = new JSONObject(r);
                RETURN_CODE = result.getString("RETURN_CODE");
                if(RETURN_CODE.equalsIgnoreCase(SUC_CODE)){
                    msg = RETURN_CODE + ":退款成功";
                }else{
                    msg = RETURN_CODE + ":" + result.getString(RETURN_MSG);
                }
            } else if (payPlat == 20) {//调用微信退费
                String appId = "";
                String mchid = "";//1485054752   1349649401
                if (payChannel == 1) {
                    appId = WxpayConfig.APPID_H5;
                    mchid = WxpayConfig.MCHID_H5;
                } else if (payChannel == 2) {
                    appId = WxpayConfig.APPID;
                    mchid = WxpayConfig.MCHID;
                } else if (payChannel == 3) {
                    appId = WxpayConfig.APPID_HTML;
                    mchid = WxpayConfig.MCHID_HTML;
                }
                //微信退费net/api/v1接口调用url
                String url = HOST_REFUND + "refund/wx";
                //请求参数

                //String parameter = "orderId="+orderId+"&fee="+amount+"&appid="+appId+"&mchid="+mchid;
                JSONObject parameter = new JSONObject();
                parameter.put("orderId", orderId);
                parameter.put("fee", amount);
                parameter.put("appid", appId);
                parameter.put("mchid", mchid);
                r = HttpUtil.syncPostJsonBody(url, MediaType.JSON_UTF_8, parameter.toString(), 15000);
                logger.debug("resultJsonString:" + r);
                if (r.contains("exception")) {
                    throw new Exception("连接退款服务器网络错误");
                }
                JSONObject result = new JSONObject(r);
                JSONObject weixinData = result.getJSONObject("Data");
                String resultCodeWX = weixinData.getString("result_code");
                String errCodeDes = weixinData.has("err_code_des") ? weixinData.getString("err_code_des") : "";
                int resultCode = result.getInt("ResultCode");
                if (resultCode == 1000 && resultCodeWX.equalsIgnoreCase("SUCCESS")) {
                    RETURN_CODE = SUC_CODE;
                } else {
                    RETURN_CODE = String.valueOf(resultCode);
                    msg = errCodeDes;
                }
            } else if (payPlat == 14) {

                //支付宝退费net/api/v1接口调用url
                String url = HOST_REFUND + "refund/ali";
                JSONObject parameter = new JSONObject();
                parameter.put("orderId", orderId);
                parameter.put("fee", amount);
                r = HttpUtil.syncPostJsonBody(url, MediaType.JSON_UTF_8, parameter.toString(), 15000);
                JSONObject aliResult = new JSONObject(r);
                JSONObject aliData = aliResult.getJSONObject("Data");
                String resultCodeALI = aliData.getString("fund_change");
                String codeALI = aliData.getString("code");//支付宝返回码
                int resultCode = aliResult.getInt("ResultCode");
                if (resultCode == 1000 && "10000".equals(codeALI) && resultCodeALI.equalsIgnoreCase("Y")) {
                    RETURN_CODE = SUC_CODE;
                } else {
                    RETURN_CODE = String.valueOf(resultCode);
                    msg = aliData.getString("msg");
                }
            } else if (payPlat == 25) {
                //TODO:农行
            }
            logger.debug("resultJsonString:" + r);
            if (r.contains("exception")) {
                throw new Exception("连接退款服务器网络错误");
            }
            if (RETURN_CODE.equals(SUC_CODE)) {
                // 成功则修改订单状态。
                updateOrder(orderId, true, "退费成功:" + r);
                jo = setResponseObj(ClientApiConstant.ResultCode.SUCCESS_CODE, "退款成功", ClientApiConstant.Msg.EMPTY);
            } else {
                // 失败则提示原因
                updateOrder(orderId, false, msg);
                jo = setResponseObj(ClientApiConstant.ResultCode.FAILED, msg, ClientApiConstant.Msg.EMPTY);
            }
        } catch (CheckOrderException e) {
            // 订单不能发起退费的情况，不能修改订单支付状态为退费失败，否则再下次就可以退费了。
            jo = setResponseObj(ClientApiConstant.ResultCode.SERVER_EXCEPTION, e.getMessage(),
                    ClientApiConstant.Msg.EMPTY);
            e.printStackTrace();
        } catch (Exception e) {
            // 请求没有响应或者出错，提示原因
            jo = setResponseObj(ClientApiConstant.ResultCode.SERVER_EXCEPTION, e.getMessage(),
                    ClientApiConstant.Msg.EMPTY);
            String errMsg = "" + e.getMessage();
            updateOrder(orderId, false, (errMsg.length() > 50 ? errMsg.substring(0, 50) : errMsg));
            e.printStackTrace();
        }
        return jo;
    }


    /**
     * @param orderId
     * @return String
     * @Title: getServiceType
     * @Description:TODO
     */
    private String getServiceType(String orderId) {
        if (StrKit.notBlank(orderId)) {
            if (orderId.startsWith(Constant.PayServiceType.RECHARGE)) {
                return Constant.PayServiceType.RECHARGE;
            } else if (orderId.startsWith(Constant.PayServiceType.PACKAGE)) {
                return Constant.PayServiceType.PACKAGE;
            }
        }
        return null;
    }

    private org.json.JSONObject setResponseObj(int code, String msg, Object data) {
        JSONObject json = new org.json.JSONObject();
        json.put(H5ApiConstant.Key.RESULT_CODE, code);
        json.put(H5ApiConstant.Key.MESSAGE, msg);
        if (data != null) {
            json.put(H5ApiConstant.Key.DATA, data);
        }
        return json;
    }

    private boolean checkOrder(String orderId, String amount) throws Exception {
        if (orderId.startsWith(Constant.PayServiceType.PACKAGE)) {
            return checkCmccOrder(orderId, amount);
        } else if (orderId.startsWith(Constant.PayServiceType.RECHARGE)) {
            return checkRechargeOrder(orderId, amount);
        }
        throw new Exception(ILLEGAL_ORDER + ":" + orderId);
    }


    private boolean checkCmccOrder(String orderId, String amount) throws Exception {
        CmccOrder record = CmccOrder.dao.getOrderInfo(orderId);
        if (record == null) {
            throw new CheckOrderException(ORDER_NOT_EXIST);
        }
        int payStatus = record.getInt(CmccOrder.PAY_STATUS);
        // 已支付或者退款失败的，才能执行退款。其他（未支付已退款等）均不能再退款。
        if ((payStatus != CmccOrder.PAID) && (payStatus != CmccOrder.REFUND_FAILED)) {
            throw new CheckOrderException(PAY_STATUS_ERROR + payStatus);
        }
        Double payAmount = record.getDouble(CmccOrder.PAY_AMOUNT);
        if (payAmount.compareTo(Double.valueOf(amount)) < 0) {
            throw new CheckOrderException(AMOUNT_ERROR + ":payAmount=" + payAmount + ":amount=" + amount);
        }
        return true;
    }


    private boolean checkRechargeOrder(String orderId, String amount) throws Exception {
        RechargeOrder record = RechargeOrder.dao.getRechargeOrderByOrderId(orderId);
        if (record == null) {
            throw new CheckOrderException(ORDER_NOT_EXIST);
        }
        int payStatus = record.getInt(RechargeOrder.PAY_STATUS);
        // 已支付或者退款失败的才能执行退款。其他（未支付已退款等）均不能再退款。
        if ((payStatus != RechargeOrder.PAID) && (payStatus != RechargeOrder.REFUND_FAILED)) {
            throw new CheckOrderException(PAY_STATUS_ERROR + payStatus);
        }
        Double payAmount = record.getDouble(RechargeOrder.PAY_AMOUNT);
        if (payAmount.compareTo(Double.valueOf(amount)) < 0) {
            throw new CheckOrderException(AMOUNT_ERROR + ":payAmount=" + payAmount + ":amount=" + amount);
        }
        return true;
    }


    private void updateOrder(String orderId, boolean result, String msg) {
        if (orderId.startsWith(Constant.PayServiceType.PACKAGE)) {
            CmccOrder.dao.updateRefund(orderId, result ? CmccOrder.REFUNDED : CmccOrder.REFUND_FAILED, msg, result);
        } else if (orderId.startsWith(Constant.PayServiceType.RECHARGE)) {
            RechargeOrder.dao.updateRefund(orderId, result ? RechargeOrder.REFUNDED : RechargeOrder.REFUND_FAILED, msg,
                    result);
        }
    }


    /**
     * 获取建行退费url
     *
     * @return
     */
    private String getCCBRefundUrl() {
        String url = "";
        List<Record> list = SysCodeType.dao.getSysCodeTypeByCode("CCB_REFUND_URL");
        if (list.size() > 0) {
            url = list.get(0).getStr(SysCodeValue.VALUE);
            logger.info("ccb refund url:" + url);
            return url;
        }
        return url;

    }


}
